home *** CD-ROM | disk | FTP | other *** search
- // BEGIN FLOCK GPL
- //
- // Copyright Flock Inc. 2005-2007
- // http://flock.com
- //
- // This file may be used under the terms of of the
- // GNU General Public License Version 2 or later (the "GPL"),
- // http://www.gnu.org/licenses/gpl.html
- //
- // Software distributed under the License is distributed on an "AS IS" basis,
- // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- // for the specific language governing rights and limitations under the
- // License.
- //
- // END FLOCK GPL
-
- const CC = Components.classes;
- const CI = Components.interfaces;
- const CR = Components.results;
-
- var EXPORTED_SYMBOLS = ["FlockScheduler"];
-
- /**
- * FlockScheduler.schedule() - A cheap scheduler for javascript tasks.
- *
- * @param object[] aTimers (in) (optional)
- * If provided, any timers created will be stored in this array
- * so the caller can cancel them early.
- * @param float aSlice (in)
- * Maximum timeslice in seconds. 0.5 or less is a good value.
- * @param float aPercent (in)
- * Percent of wall-clock time that should be spent executing the task.
- * For example, 20 = one fifth of the time.
- * @param function aTask (in)
- * A generator taking a function that evaluates to true if it should
- * yield, like this:
- *
- * function task(should_yield) {
- * while (some_condition) {
- * do some work...
- * if (should_yield()) {
- * yield;
- * }
- * }
- * }
- *
- * @return nothing
- *
- * NOTE: should_yield() is fairly cheap but in a tight inner loop it might
- * make sense to call it every N cycles
- */
- var FlockScheduler = {
- schedule: function schedule(aTimers, aSlice, aPercent, aTask) {
-
- // convert percent to ratio
- var ratio = aPercent / 100.0;
-
- // convert slice to milliseconds
- var slice = aSlice * 1000.0;
-
- // A helper to get the current time as milliseconds.
- function milliseconds() { return (new Date ()).getTime(); }
- var wall_start = milliseconds();
- var process_time = 0;
- var process_start = 0;
-
- // A function the task can use to decide whether to yield its timeslice.
- function should_yield() {
- var now = milliseconds();
- var so_far = now - process_start;
- var wall_time = now - wall_start;
- return (so_far >= slice) ||
- ((wall_time * ratio) < (process_time + so_far));
- }
-
- // A generator is (among other things) a function that calls yield().
- // To resume execution at the point of suspension by yield(), call the
- // generator's .next() method.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=326466
- var generator = aTask(should_yield);
- var timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
-
- var callback = {
- notify: function FlockScheduler_callback_notify() {
- var wall_time = milliseconds() - wall_start;
-
- if (process_time > (wall_time * ratio)) {
- // We've spent more time than we're supposed to; skip this cycle.
- return;
- }
-
- process_start = milliseconds();
- try {
- // Resume execution where the function yield()ed.
- generator.next();
- } catch (err if err instanceof StopIteration) {
- // The task is complete; stop timer and destroy it.
- timer.cancel();
- if (aTimers) {
- for (var i = 0; i < aTimers.length; i++) {
- if (aTimers[i] === timer) {
- aTimers.splice(i, 1);
- }
- }
- }
- timer = null;
- }
- process_time += (milliseconds() - process_start);
- }
- };
-
- timer.initWithCallback(callback,
- Math.round(slice/ratio),
- CI.nsITimer.TYPE_REPEATING_SLACK);
- if (aTimers) {
- aTimers.push(timer);
- }
- }
- };
-